/* Blowfish Cipher
Copyright (C) 1997 Paul Kocher.
Copyright (C) 2009-2018 Manuel Sainz de Baranda y Goñi.
Released under the terms of the GNU Lesser General Public License v3. */

#if defined(CIPHER_BLOWFISH_HIDE_API)
#	define CIPHER_BLOWFISH_API static
#elif defined(CIPHER_BLOWFISH_STATIC)
#	define CIPHER_BLOWFISH_API
#else
#	define CIPHER_BLOWFISH_API Z_API_EXPORT
#endif

#if defined(CIPHER_BLOWFISH_HIDE_ABI)
#	define CIPHER_BLOWFISH_ABI static
#elif defined(CIPHER_BLOWFISH_STATIC)
#	define CIPHER_BLOWFISH_ABI
#else
#	define CIPHER_BLOWFISH_ABI Z_API_EXPORT
#endif

#define CIPHER_BLOWFISH_OMIT_FUNCTION_PROTOTYPES

#if defined(CIPHER_BLOWFISH_USE_LOCAL_HEADER)
#	include "Blowfish.h"
#else
#	include <cipher/Blowfish.h>
#endif

#include <Z/functions/base/value.h>

#define C(value) Z_UINT32(0x##value)

static zuint32 const p[16 + 2] = {
	C(243F6A88), C(85A308D3), C(13198A2E), C(03707344),
	C(A4093822), C(299F31D0), C(082EFA98), C(EC4E6C89),
	C(452821E6), C(38D01377), C(BE5466CF), C(34E90C6C),
	C(C0AC29B7), C(C97C50DD), C(3F84D5B5), C(B5470917),
	C(9216D5D9), C(8979FB1B)
};

static zuint32 const s[4][256] = {
       {C(D1310BA6), C(98DFB5AC), C(2FFD72DB), C(D01ADFB7),
	C(B8E1AFED), C(6A267E96), C(BA7C9045), C(F12C7F99),
	C(24A19947), C(B3916CF7), C(0801F2E2), C(858EFC16),
	C(636920D8), C(71574E69), C(A458FEA3), C(F4933D7E),
	C(0D95748F), C(728EB658), C(718BCD58), C(82154AEE),
	C(7B54A41D), C(C25A59B5), C(9C30D539), C(2AF26013),
	C(C5D1B023), C(286085F0), C(CA417918), C(B8DB38EF),
	C(8E79DCB0), C(603A180E), C(6C9E0E8B), C(B01E8A3E),
	C(D71577C1), C(BD314B27), C(78AF2FDA), C(55605C60),
	C(E65525F3), C(AA55AB94), C(57489862), C(63E81440),
	C(55CA396A), C(2AAB10B6), C(B4CC5C34), C(1141E8CE),
	C(A15486AF), C(7C72E993), C(B3EE1411), C(636FBC2A),
	C(2BA9C55D), C(741831F6), C(CE5C3E16), C(9B87931E),
	C(AFD6BA33), C(6C24CF5C), C(7A325381), C(28958677),
	C(3B8F4898), C(6B4BB9AF), C(C4BFE81B), C(66282193),
	C(61D809CC), C(FB21A991), C(487CAC60), C(5DEC8032),
	C(EF845D5D), C(E98575B1), C(DC262302), C(EB651B88),
	C(23893E81), C(D396ACC5), C(0F6D6FF3), C(83F44239),
	C(2E0B4482), C(A4842004), C(69C8F04A), C(9E1F9B5E),
	C(21C66842), C(F6E96C9A), C(670C9C61), C(ABD388F0),
	C(6A51A0D2), C(D8542F68), C(960FA728), C(AB5133A3),
	C(6EEF0B6C), C(137A3BE4), C(BA3BF050), C(7EFB2A98),
	C(A1F1651D), C(39AF0176), C(66CA593E), C(82430E88),
	C(8CEE8619), C(456F9FB4), C(7D84A5C3), C(3B8B5EBE),
	C(E06F75D8), C(85C12073), C(401A449F), C(56C16AA6),
	C(4ED3AA62), C(363F7706), C(1BFEDF72), C(429B023D),
	C(37D0D724), C(D00A1248), C(DB0FEAD3), C(49F1C09B),
	C(075372C9), C(80991B7B), C(25D479D8), C(F6E8DEF7),
	C(E3FE501A), C(B6794C3B), C(976CE0BD), C(04C006BA),
	C(C1A94FB6), C(409F60C4), C(5E5C9EC2), C(196A2463),
	C(68FB6FAF), C(3E6C53B5), C(1339B2EB), C(3B52EC6F),
	C(6DFC511F), C(9B30952C), C(CC814544), C(AF5EBD09),
	C(BEE3D004), C(DE334AFD), C(660F2807), C(192E4BB3),
	C(C0CBA857), C(45C8740F), C(D20B5F39), C(B9D3FBDB),
	C(5579C0BD), C(1A60320A), C(D6A100C6), C(402C7279),
	C(679F25FE), C(FB1FA3CC), C(8EA5E9F8), C(DB3222F8),
	C(3C7516DF), C(FD616B15), C(2F501EC8), C(AD0552AB),
	C(323DB5FA), C(FD238760), C(53317B48), C(3E00DF82),
	C(9E5C57BB), C(CA6F8CA0), C(1A87562E), C(DF1769DB),
	C(D542A8F6), C(287EFFC3), C(AC6732C6), C(8C4F5573),
	C(695B27B0), C(BBCA58C8), C(E1FFA35D), C(B8F011A0),
	C(10FA3D98), C(FD2183B8), C(4AFCB56C), C(2DD1D35B),
	C(9A53E479), C(B6F84565), C(D28E49BC), C(4BFB9790),
	C(E1DDF2DA), C(A4CB7E33), C(62FB1341), C(CEE4C6E8),
	C(EF20CADA), C(36774C01), C(D07E9EFE), C(2BF11FB4),
	C(95DBDA4D), C(AE909198), C(EAAD8E71), C(6B93D5A0),
	C(D08ED1D0), C(AFC725E0), C(8E3C5B2F), C(8E7594B7),
	C(8FF6E2FB), C(F2122B64), C(8888B812), C(900DF01C),
	C(4FAD5EA0), C(688FC31C), C(D1CFF191), C(B3A8C1AD),
	C(2F2F2218), C(BE0E1777), C(EA752DFE), C(8B021FA1),
	C(E5A0CC0F), C(B56F74E8), C(18ACF3D6), C(CE89E299),
	C(B4A84FE0), C(FD13E0B7), C(7CC43B81), C(D2ADA8D9),
	C(165FA266), C(80957705), C(93CC7314), C(211A1477),
	C(E6AD2065), C(77B5FA86), C(C75442F5), C(FB9D35CF),
	C(EBCDAF0C), C(7B3E89A0), C(D6411BD3), C(AE1E7E49),
	C(00250E2D), C(2071B35E), C(226800BB), C(57B8E0AF),
	C(2464369B), C(F009B91E), C(5563911D), C(59DFA6AA),
	C(78C14389), C(D95A537F), C(207D5BA2), C(02E5B9C5),
	C(83260376), C(6295CFA9), C(11C81968), C(4E734A41),
	C(B3472DCA), C(7B14A94A), C(1B510052), C(9A532915),
	C(D60F573F), C(BC9BC6E4), C(2B60A476), C(81E67400),
	C(08BA6FB5), C(571BE91F), C(F296EC6B), C(2A0DD915),
	C(B6636521), C(E7B9F9B6), C(FF34052E), C(C5855664),
	C(53B02D5D), C(A99F8FA1), C(08BA4799), C(6E85076A)},

       {C(4B7A70E9), C(B5B32944), C(DB75092E), C(C4192623),
	C(AD6EA6B0), C(49A7DF7D), C(9CEE60B8), C(8FEDB266),
	C(ECAA8C71), C(699A17FF), C(5664526C), C(C2B19EE1),
	C(193602A5), C(75094C29), C(A0591340), C(E4183A3E),
	C(3F54989A), C(5B429D65), C(6B8FE4D6), C(99F73FD6),
	C(A1D29C07), C(EFE830F5), C(4D2D38E6), C(F0255DC1),
	C(4CDD2086), C(8470EB26), C(6382E9C6), C(021ECC5E),
	C(09686B3F), C(3EBAEFC9), C(3C971814), C(6B6A70A1),
	C(687F3584), C(52A0E286), C(B79C5305), C(AA500737),
	C(3E07841C), C(7FDEAE5C), C(8E7D44EC), C(5716F2B8),
	C(B03ADA37), C(F0500C0D), C(F01C1F04), C(0200B3FF),
	C(AE0CF51A), C(3CB574B2), C(25837A58), C(DC0921BD),
	C(D19113F9), C(7CA92FF6), C(94324773), C(22F54701),
	C(3AE5E581), C(37C2DADC), C(C8B57634), C(9AF3DDA7),
	C(A9446146), C(0FD0030E), C(ECC8C73E), C(A4751E41),
	C(E238CD99), C(3BEA0E2F), C(3280BBA1), C(183EB331),
	C(4E548B38), C(4F6DB908), C(6F420D03), C(F60A04BF),
	C(2CB81290), C(24977C79), C(5679B072), C(BCAF89AF),
	C(DE9A771F), C(D9930810), C(B38BAE12), C(DCCF3F2E),
	C(5512721F), C(2E6B7124), C(501ADDE6), C(9F84CD87),
	C(7A584718), C(7408DA17), C(BC9F9ABC), C(E94B7D8C),
	C(EC7AEC3A), C(DB851DFA), C(63094366), C(C464C3D2),
	C(EF1C1847), C(3215D908), C(DD433B37), C(24C2BA16),
	C(12A14D43), C(2A65C451), C(50940002), C(133AE4DD),
	C(71DFF89E), C(10314E55), C(81AC77D6), C(5F11199B),
	C(043556F1), C(D7A3C76B), C(3C11183B), C(5924A509),
	C(F28FE6ED), C(97F1FBFA), C(9EBABF2C), C(1E153C6E),
	C(86E34570), C(EAE96FB1), C(860E5E0A), C(5A3E2AB3),
	C(771FE71C), C(4E3D06FA), C(2965DCB9), C(99E71D0F),
	C(803E89D6), C(5266C825), C(2E4CC978), C(9C10B36A),
	C(C6150EBA), C(94E2EA78), C(A5FC3C53), C(1E0A2DF4),
	C(F2F74EA7), C(361D2B3D), C(1939260F), C(19C27960),
	C(5223A708), C(F71312B6), C(EBADFE6E), C(EAC31F66),
	C(E3BC4595), C(A67BC883), C(B17F37D1), C(018CFF28),
	C(C332DDEF), C(BE6C5AA5), C(65582185), C(68AB9802),
	C(EECEA50F), C(DB2F953B), C(2AEF7DAD), C(5B6E2F84),
	C(1521B628), C(29076170), C(ECDD4775), C(619F1510),
	C(13CCA830), C(EB61BD96), C(0334FE1E), C(AA0363CF),
	C(B5735C90), C(4C70A239), C(D59E9E0B), C(CBAADE14),
	C(EECC86BC), C(60622CA7), C(9CAB5CAB), C(B2F3846E),
	C(648B1EAF), C(19BDF0CA), C(A02369B9), C(655ABB50),
	C(40685A32), C(3C2AB4B3), C(319EE9D5), C(C021B8F7),
	C(9B540B19), C(875FA099), C(95F7997E), C(623D7DA8),
	C(F837889A), C(97E32D77), C(11ED935F), C(16681281),
	C(0E358829), C(C7E61FD6), C(96DEDFA1), C(7858BA99),
	C(57F584A5), C(1B227263), C(9B83C3FF), C(1AC24696),
	C(CDB30AEB), C(532E3054), C(8FD948E4), C(6DBC3128),
	C(58EBF2EF), C(34C6FFEA), C(FE28ED61), C(EE7C3C73),
	C(5D4A14D9), C(E864B7E3), C(42105D14), C(203E13E0),
	C(45EEE2B6), C(A3AAABEA), C(DB6C4F15), C(FACB4FD0),
	C(C742F442), C(EF6ABBB5), C(654F3B1D), C(41CD2105),
	C(D81E799E), C(86854DC7), C(E44B476A), C(3D816250),
	C(CF62A1F2), C(5B8D2646), C(FC8883A0), C(C1C7B6A3),
	C(7F1524C3), C(69CB7492), C(47848A0B), C(5692B285),
	C(095BBF00), C(AD19489D), C(1462B174), C(23820E00),
	C(58428D2A), C(0C55F5EA), C(1DADF43E), C(233F7061),
	C(3372F092), C(8D937E41), C(D65FECF1), C(6C223BDB),
	C(7CDE3759), C(CBEE7460), C(4085F2A7), C(CE77326E),
	C(A6078084), C(19F8509E), C(E8EFD855), C(61D99735),
	C(A969A7AA), C(C50C06C2), C(5A04ABFC), C(800BCADC),
	C(9E447A2E), C(C3453484), C(FDD56705), C(0E1E9EC9),
	C(DB73DBD3), C(105588CD), C(675FDA79), C(E3674340),
	C(C5C43465), C(713E38D8), C(3D28F89E), C(F16DFF20),
	C(153E21E7), C(8FB03D4A), C(E6E39F2B), C(DB83ADF7)},

       {C(E93D5A68), C(948140F7), C(F64C261C), C(94692934),
	C(411520F7), C(7602D4F7), C(BCF46B2E), C(D4A20068),
	C(D4082471), C(3320F46A), C(43B7D4B7), C(500061AF),
	C(1E39F62E), C(97244546), C(14214F74), C(BF8B8840),
	C(4D95FC1D), C(96B591AF), C(70F4DDD3), C(66A02F45),
	C(BFBC09EC), C(03BD9785), C(7FAC6DD0), C(31CB8504),
	C(96EB27B3), C(55FD3941), C(DA2547E6), C(ABCA0A9A),
	C(28507825), C(530429F4), C(0A2C86DA), C(E9B66DFB),
	C(68DC1462), C(D7486900), C(680EC0A4), C(27A18DEE),
	C(4F3FFEA2), C(E887AD8C), C(B58CE006), C(7AF4D6B6),
	C(AACE1E7C), C(D3375FEC), C(CE78A399), C(406B2A42),
	C(20FE9E35), C(D9F385B9), C(EE39D7AB), C(3B124E8B),
	C(1DC9FAF7), C(4B6D1856), C(26A36631), C(EAE397B2),
	C(3A6EFA74), C(DD5B4332), C(6841E7F7), C(CA7820FB),
	C(FB0AF54E), C(D8FEB397), C(454056AC), C(BA489527),
	C(55533A3A), C(20838D87), C(FE6BA9B7), C(D096954B),
	C(55A867BC), C(A1159A58), C(CCA92963), C(99E1DB33),
	C(A62A4A56), C(3F3125F9), C(5EF47E1C), C(9029317C),
	C(FDF8E802), C(04272F70), C(80BB155C), C(05282CE3),
	C(95C11548), C(E4C66D22), C(48C1133F), C(C70F86DC),
	C(07F9C9EE), C(41041F0F), C(404779A4), C(5D886E17),
	C(325F51EB), C(D59BC0D1), C(F2BCC18F), C(41113564),
	C(257B7834), C(602A9C60), C(DFF8E8A3), C(1F636C1B),
	C(0E12B4C2), C(02E1329E), C(AF664FD1), C(CAD18115),
	C(6B2395E0), C(333E92E1), C(3B240B62), C(EEBEB922),
	C(85B2A20E), C(E6BA0D99), C(DE720C8C), C(2DA2F728),
	C(D0127845), C(95B794FD), C(647D0862), C(E7CCF5F0),
	C(5449A36F), C(877D48FA), C(C39DFD27), C(F33E8D1E),
	C(0A476341), C(992EFF74), C(3A6F6EAB), C(F4F8FD37),
	C(A812DC60), C(A1EBDDF8), C(991BE14C), C(DB6E6B0D),
	C(C67B5510), C(6D672C37), C(2765D43B), C(DCD0E804),
	C(F1290DC7), C(CC00FFA3), C(B5390F92), C(690FED0B),
	C(667B9FFB), C(CEDB7D9C), C(A091CF0B), C(D9155EA3),
	C(BB132F88), C(515BAD24), C(7B9479BF), C(763BD6EB),
	C(37392EB3), C(CC115979), C(8026E297), C(F42E312D),
	C(6842ADA7), C(C66A2B3B), C(12754CCC), C(782EF11C),
	C(6A124237), C(B79251E7), C(06A1BBE6), C(4BFB6350),
	C(1A6B1018), C(11CAEDFA), C(3D25BDD8), C(E2E1C3C9),
	C(44421659), C(0A121386), C(D90CEC6E), C(D5ABEA2A),
	C(64AF674E), C(DA86A85F), C(BEBFE988), C(64E4C3FE),
	C(9DBC8057), C(F0F7C086), C(60787BF8), C(6003604D),
	C(D1FD8346), C(F6381FB0), C(7745AE04), C(D736FCCC),
	C(83426B33), C(F01EAB71), C(B0804187), C(3C005E5F),
	C(77A057BE), C(BDE8AE24), C(55464299), C(BF582E61),
	C(4E58F48F), C(F2DDFDA2), C(F474EF38), C(8789BDC2),
	C(5366F9C3), C(C8B38E74), C(B475F255), C(46FCD9B9),
	C(7AEB2661), C(8B1DDF84), C(846A0E79), C(915F95E2),
	C(466E598E), C(20B45770), C(8CD55591), C(C902DE4C),
	C(B90BACE1), C(BB8205D0), C(11A86248), C(7574A99E),
	C(B77F19B6), C(E0A9DC09), C(662D09A1), C(C4324633),
	C(E85A1F02), C(09F0BE8C), C(4A99A025), C(1D6EFE10),
	C(1AB93D1D), C(0BA5A4DF), C(A186F20F), C(2868F169),
	C(DCB7DA83), C(573906FE), C(A1E2CE9B), C(4FCD7F52),
	C(50115E01), C(A70683FA), C(A002B5C4), C(0DE6D027),
	C(9AF88C27), C(773F8641), C(C3604C06), C(61A806B5),
	C(F0177A28), C(C0F586E0), C(006058AA), C(30DC7D62),
	C(11E69ED7), C(2338EA63), C(53C2DD94), C(C2C21634),
	C(BBCBEE56), C(90BCB6DE), C(EBFC7DA1), C(CE591D76),
	C(6F05E409), C(4B7C0188), C(39720A3D), C(7C927C24),
	C(86E3725F), C(724D9DB9), C(1AC15BB4), C(D39EB8FC),
	C(ED545578), C(08FCA5B5), C(D83D7CD3), C(4DAD0FC4),
	C(1E50EF5E), C(B161E6F8), C(A28514D9), C(6C51133C),
	C(6FD5C7E7), C(56E14EC4), C(362ABFCE), C(DDC6C837),
	C(D79A3234), C(92638212), C(670EFA8E), C(406000E0)},

       {C(3A39CE37), C(D3FAF5CF), C(ABC27737), C(5AC52D1B),
	C(5CB0679E), C(4FA33742), C(D3822740), C(99BC9BBE),
	C(D5118E9D), C(BF0F7315), C(D62D1C7E), C(C700C47B),
	C(B78C1B6B), C(21A19045), C(B26EB1BE), C(6A366EB4),
	C(5748AB2F), C(BC946E79), C(C6A376D2), C(6549C2C8),
	C(530FF8EE), C(468DDE7D), C(D5730A1D), C(4CD04DC6),
	C(2939BBDB), C(A9BA4650), C(AC9526E8), C(BE5EE304),
	C(A1FAD5F0), C(6A2D519A), C(63EF8CE2), C(9A86EE22),
	C(C089C2B8), C(43242EF6), C(A51E03AA), C(9CF2D0A4),
	C(83C061BA), C(9BE96A4D), C(8FE51550), C(BA645BD6),
	C(2826A2F9), C(A73A3AE1), C(4BA99586), C(EF5562E9),
	C(C72FEFD3), C(F752F7DA), C(3F046F69), C(77FA0A59),
	C(80E4A915), C(87B08601), C(9B09E6AD), C(3B3EE593),
	C(E990FD5A), C(9E34D797), C(2CF0B7D9), C(022B8B51),
	C(96D5AC3A), C(017DA67D), C(D1CF3ED6), C(7C7D2D28),
	C(1F9F25CF), C(ADF2B89B), C(5AD6B472), C(5A88F54C),
	C(E029AC71), C(E019A5E6), C(47B0ACFD), C(ED93FA9B),
	C(E8D3C48D), C(283B57CC), C(F8D56629), C(79132E28),
	C(785F0191), C(ED756055), C(F7960E44), C(E3D35E8C),
	C(15056DD4), C(88F46DBA), C(03A16125), C(0564F0BD),
	C(C3EB9E15), C(3C9057A2), C(97271AEC), C(A93A072A),
	C(1B3F6D9B), C(1E6321F5), C(F59C66FB), C(26DCF319),
	C(7533D928), C(B155FDF5), C(03563482), C(8ABA3CBB),
	C(28517711), C(C20AD9F8), C(ABCC5167), C(CCAD925F),
	C(4DE81751), C(3830DC8E), C(379D5862), C(9320F991),
	C(EA7A90C2), C(FB3E7BCE), C(5121CE64), C(774FBE32),
	C(A8B6E37E), C(C3293D46), C(48DE5369), C(6413E680),
	C(A2AE0810), C(DD6DB224), C(69852DFD), C(09072166),
	C(B39A460A), C(6445C0DD), C(586CDECF), C(1C20C8AE),
	C(5BBEF7DD), C(1B588D40), C(CCD2017F), C(6BB4E3BB),
	C(DDA26A7E), C(3A59FF45), C(3E350A44), C(BCB4CDD5),
	C(72EACEA8), C(FA6484BB), C(8D6612AE), C(BF3C6F47),
	C(D29BE463), C(542F5D9E), C(AEC2771B), C(F64E6370),
	C(740E0D8D), C(E75B1357), C(F8721671), C(AF537D5D),
	C(4040CB08), C(4EB4E2CC), C(34D2466A), C(0115AF84),
	C(E1B00428), C(95983A1D), C(06B89FB4), C(CE6EA048),
	C(6F3F3B82), C(3520AB82), C(011A1D4B), C(277227F8),
	C(611560B1), C(E7933FDC), C(BB3A792B), C(344525BD),
	C(A08839E1), C(51CE794B), C(2F32C9B7), C(A01FBAC9),
	C(E01CC87E), C(BCC7D1F6), C(CF0111C3), C(A1E8AAC7),
	C(1A908749), C(D44FBD9A), C(D0DADECB), C(D50ADA38),
	C(0339C32A), C(C6913667), C(8DF9317C), C(E0B12B4F),
	C(F79E59B7), C(43F5BB3A), C(F2D519FF), C(27D9459C),
	C(BF97222C), C(15E6FC2A), C(0F91FC71), C(9B941525),
	C(FAE59361), C(CEB69CEB), C(C2A86459), C(12BAA8D1),
	C(B6C1075E), C(E3056A0C), C(10D25065), C(CB03A442),
	C(E0EC6E0E), C(1698DB3B), C(4C98A0BE), C(3278E964),
	C(9F1F9532), C(E0D392DF), C(D3A0342B), C(8971F21E),
	C(1B0A7441), C(4BA3348C), C(C5BE7120), C(C37632D8),
	C(DF359F8D), C(9B992F2E), C(E60B6F47), C(0FE3F11D),
	C(E54CDA54), C(1EDAD891), C(CE6279CF), C(CD3E7E6F),
	C(1618B166), C(FD2C1D05), C(848FD2C5), C(F6FB2299),
	C(F523F357), C(A6327623), C(93A83531), C(56CCCD02),
	C(ACF08162), C(5A75EBB5), C(6E163697), C(88D273CC),
	C(DE966292), C(81B949D0), C(4C50901B), C(71C65614),
	C(E6C6C7BD), C(327A140A), C(45E1D006), C(C3F27B9A),
	C(C9AA53FD), C(62A80F00), C(BB25BFE2), C(35BDD2F6),
	C(71126905), C(B2040222), C(B6CBCF7C), C(CD769C2B),
	C(53113EC0), C(1640E3D3), C(38ABBD60), C(2547ADF0),
	C(BA38209C), C(F746CE76), C(77AFA1C5), C(20756060),
	C(85CBFE4E), C(8AE88DD8), C(7AAAF9B0), C(4CF9AA7E),
	C(1948C25C), C(02FB8A8C), C(01C36AE4), C(D6EBE1F9),
	C(90D4F869), C(A65CDEA0), C(3F09252D), C(C208E69F),
	C(B74E6132), C(CE77E25B), C(578FDFE3), C(3AC372E6)}
};


#define F							      \
((((object->s[0][(t >> 24) & 0xFF]  + object->s[1][(t >> 16) & 0xFF]) \
  ^ object->s[2][(t >>  8) & 0xFF]) + object->s[3][ t	     & 0xFF]));


CIPHER_BLOWFISH_API
void blowfish_encipher(
	Blowfish*      object,
	zuint32 const* block,
	zusize	       block_size,
	zuint32*       output
)
	{
	zuint32 l, r, t;
	zuint i;

	for (block_size >>= 3; block_size; block_size--, block += 2, output += 2)
		{
		l = z_uint32_big_endian(block[0]);
		r = z_uint32_big_endian(block[1]);

		for (i = 0; i < 16;)
			{
			t = l ^ object->p[i++];
			l = r ^ F;
			r = t;
			}

		output[0] = z_uint32_big_endian(r ^= object->p[17]);
		output[1] = z_uint32_big_endian(l ^= object->p[16]);
		}
	}


CIPHER_BLOWFISH_API
void blowfish_decipher(
	Blowfish*      object,
	zuint32 const* block,
	zusize	       block_size,
	zuint32*       output
)
	{
	zuint32 l, r, t;
	zuint i;

	for (block_size >>= 3; block_size; block_size--, block += 2, output += 2)
		{
		l = z_uint32_big_endian(block[0]);
		r = z_uint32_big_endian(block[1]);

		for (i = 17; i > 1;)
			{
			t = l ^ object->p[i--];
			l = r ^ F;
			r = t;
			}

		output[0] = z_uint32_big_endian(r ^= object->p[0]);
		output[1] = z_uint32_big_endian(l ^= object->p[1]);
		}
	}


CIPHER_BLOWFISH_API
void blowfish_set_key(Blowfish *object, zuint8 const *key, zusize key_size)
	{
	zuint i = 0, j;
	zusize k = 0;
	zuint32 data;
	zuint32 t[2] = {0, 0};

	for (; i < 4; i++) for (j = 0; j < 256; j++) object->s[i][j] = s[i][j];

	for (i = 0; i < 18; i++)
		{
		data =	(zuint32)
			((((zuint32)key[ k		  ]) << 24) |
			 (((zuint32)key[(k + 1) % key_size]) << 16) |
			 (((zuint32)key[(k + 2) % key_size]) <<  8) |
			  ((zuint32)key[(k + 3) % key_size]));

		object->p[i] = p[i] ^ data;
		k = (k + 4) % key_size;
		}

	for (i = 0; i < 18; i += 2)
		{
		blowfish_encipher(object, t, 8, t);
		object->p[i    ] = z_uint32_big_endian(t[0]);
		object->p[i + 1] = z_uint32_big_endian(t[1]);
		}

	for (i = 0; i < 4; i++) for (j = 0; j < 256; j += 2)
		{
		blowfish_encipher(object, t, 8, t);
		object->s[i][j    ] = z_uint32_big_endian(t[0]);
		object->s[i][j + 1] = z_uint32_big_endian(t[1]);
		}
	}


#if defined(CIPHER_BLOWFISH_BUILD_ABI) || defined(CIPHER_BLOWFISH_BUILD_MODULE_ABI)

	CIPHER_BLOWFISH_ABI ZCipherABI const abi_cipher_blowfish = {
		/* test_key		 */ NULL,
		/* set_key		 */ (ZCipherSetKey )blowfish_set_key,
		/* encipher		 */ (ZCipherProcess)blowfish_encipher,
		/* decipher		 */ (ZCipherProcess)blowfish_decipher,
		/* enciphering_size	 */ NULL,
		/* deciphering_size	 */ NULL,
		/* instance_size	 */ sizeof(Blowfish),
		/* key_minimum_size	 */ BLOWFISH_KEY_MINIMUM_SIZE,
		/* key_maximum_size	 */ BLOWFISH_KEY_MAXIMUM_SIZE,
		/* key_word_size	 */ BLOWFISH_KEY_WORD_SIZE,
		/* enciphering_word_size */ BLOWFISH_WORD_SIZE,
		/* deciphering_word_size */ BLOWFISH_WORD_SIZE,
		/* features		 */ FALSE
	};

#endif

#if defined(CIPHER_BLOWFISH_BUILD_MODULE_ABI)

#	include <Z/ABIs/generic/module.h>

	static ZModuleUnit const unit = {
		"Blowfish", "Blowfish", Z_VERSION(1, 0, 0), &abi_cipher_blowfish,
	};

	static ZModuleDomain const domain = {"Cipher", Z_VERSION(1, 0, 0), 1, &unit};
	Z_API_WEAK_EXPORT ZModuleABI const __module_abi__ = {1, &domain};

#endif


/* Blowfish.c EOF */
